package com.kaver.modular.dc.controller;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.google.common.collect.Lists;
import com.kaver.core.base.controller.BaseController;
import com.kaver.core.base.tips.ErrorTip;
import com.kaver.core.common.annotion.Permission;
import com.kaver.core.common.constant.Const;
import com.kaver.core.common.constant.state.ChangeType;
import com.kaver.core.common.constant.state.ConfigStatus;
import com.kaver.core.common.exception.BizExceptionEnum;
import com.kaver.core.exception.BzException;
import com.kaver.core.log.LogObjectHolder;
import com.kaver.core.node.SelectNode;
import com.kaver.core.node.ZTreeNode;
import com.kaver.core.page.PageBT;
import com.kaver.core.page.PageInfoBT;
import com.kaver.core.shiro.ShiroKit;
import com.kaver.core.shiro.ShiroUser;
import com.kaver.core.support.CollectionKit;
import com.kaver.core.support.SafeProperties;
import com.kaver.core.util.ToolUtil;
import com.kaver.modular.dc.service.IDcAppParentService;
import com.kaver.modular.dc.service.IDcAppService;
import com.kaver.modular.dc.service.IDcConfigService;
import com.kaver.modular.dc.service.IDcConfigVersionService;
import com.kaver.modular.dc.service.IDcEnvRoleService;
import com.kaver.modular.dc.service.IDcEnvService;
import com.kaver.modular.dc.service.IDcVersionService;
import com.kaver.modular.system.model.DcApp;
import com.kaver.modular.system.model.DcAppParent;
import com.kaver.modular.system.model.DcConfig;
import com.kaver.modular.system.model.DcConfigVersion;
import com.kaver.modular.system.model.DcEnv;
import com.kaver.modular.system.model.DcEnvRole;
import com.kaver.modular.system.model.DcVersion;
import com.kaver.modular.system.transfer.AddConfigReq;
import com.kaver.modular.system.transfer.ConfigDto;

/**
 * 配置项控制器
 *
 * @author Roc
 * @Date 2019-01-29 10:42:37
 */
@Controller
@RequestMapping("/dcConfig")
public class DcConfigController extends BaseController {

	private String PREFIX = "/dc/dcConfig/";

	@Autowired
	private IDcConfigService dcConfigService;
	@Autowired
	private IDcAppService dcAppService;
	@Autowired
	private IDcEnvService dcEnvService;
	@Autowired
	private IDcVersionService dcVersionService;
	@Autowired
	private IDcConfigVersionService dcConfigVersionService;
	@Autowired
	IDcAppParentService dcAppParentService;
	@Autowired
	IDcEnvRoleService envRoleService;
	@Autowired
	private RedisTemplate<String, Object> redisTemplate;

	/**
	 * 跳转到配置项首页
	 */
	@RequestMapping("")
	public String index() {
		return PREFIX + "dcConfig.html";
	}

	/**
	 * 跳转到添加配置项
	 */
	@RequestMapping("/dcConfig_add")
	public String dcConfigAdd(Integer appId, Integer envId, Model model) {
		DcConfig dcConfig = new DcConfig();
		dcConfig.setAppId(appId);
		dcConfig.setEnvId(envId);
		model.addAttribute("item", dcConfig);
		LogObjectHolder.me().set(dcConfig);
		return PREFIX + "dcConfig_add.html";
	}

	/**
	 * 跳转到文件上传
	 */
	@RequestMapping("/dcConfig_upload")
	public String dcConfigUpload(Integer appId, Integer envId, Model model) {
		DcConfig dcConfig = new DcConfig();
		dcConfig.setAppId(appId);
		dcConfig.setEnvId(envId);
		model.addAttribute("item", dcConfig);
		LogObjectHolder.me().set(dcConfig);
		return PREFIX + "dcConfig_upload.html";
	}

	/**
	 * 跳转到父项目
	 */
	@RequestMapping("/dcConfig_parent")
	public String dcConfigParent(Integer appId, Integer envId, Model model) {
		if (ToolUtil.isEmpty(appId)) {
			throw new BzException(BizExceptionEnum.REQUEST_NULL);
		}
		DcApp app = dcAppService.selectById(appId);
		model.addAttribute("envId", envId);
		model.addAttribute("appId", appId);
		model.addAttribute("appName", app.getAppName());
		return PREFIX + "dcConfig_parent.html";
	}

	/**
	 * 设置父项目
	 */
	@Permission
	@RequestMapping(value = "/setParent")
	@ResponseBody
	@Transactional
	public Object setParent(@RequestParam Integer appId, @RequestParam Integer envId, @RequestParam String parentIds) {
		String[] ids = parentIds.split(",");
		List<String> idsNew = null;
		if (StringUtils.isEmpty(parentIds) || ids == null || ids.length < 1) {
			idsNew = new ArrayList<>();
		} else {
			idsNew = Arrays.asList(ids);
		}
		DcApp app = dcAppService.selectById(appId);
		if (app == null) {
			return new ErrorTip(500, "项目不存在");
		}
		ShiroUser user = ShiroKit.getUser();
		DcAppParent entity = new DcAppParent();
		entity.setAppId(appId);
		entity.setEnvId(envId);
		Wrapper<DcAppParent> wrapper = new EntityWrapper<DcAppParent>(entity);
		List<DcAppParent> appParents = dcAppParentService.selectList(wrapper);// 获取原始关系
		List<Integer> old = new ArrayList<>();
		appParents.forEach(action -> old.add(action.getParentAppId()));
		List<Integer> add = new ArrayList<>();
		for (String newid : idsNew) {
			if (!old.contains(Integer.valueOf(newid))) {
				add.add(Integer.valueOf(newid));
			}
		}
		List<Integer> del = new ArrayList<>();
		for (Integer oldId : old) {
			if (!idsNew.contains(String.valueOf(oldId))) {
				del.add(oldId);
			}
		}
		// 删除原始数据
		dcAppParentService.delete(wrapper);
		List<DcAppParent> entityList = new ArrayList<>();
		for (String id : idsNew) {
			DcAppParent appParent = new DcAppParent();
			appParent.setAppId(appId);
			appParent.setCreateTime(new Date());
			appParent.setParentAppId(Integer.valueOf(id));
			appParent.setEnvId(envId);
			entityList.add(appParent);
		}
		if (!CollectionUtils.isEmpty(entityList)) {
			dcAppParentService.insertBatch(entityList);
		}
		// 发布版本
		pub(appId, envId, add, del, user);
		return SUCCESS_TIP;
	}
	//更改父项目直接发布父项目配置 包含删除和新增的配置
	private void pub(Integer appId, Integer envId, List<Integer> add, List<Integer> del, ShiroUser user) {
		if (!CollectionUtils.isEmpty(add) || !CollectionUtils.isEmpty(del)) {
			DcVersion version = new DcVersion();
			version.setCreateTime(new Date());
			dcVersionService.insert(version);
			List<DcConfigVersion> configVersions = new ArrayList<>();
			if (!CollectionUtils.isEmpty(add)) {
				List<DcConfigVersion> versions = this.getDcConfigVersion(add, envId);// 获取新增的配置
				for (DcConfigVersion configVersion : versions) {
					DcConfigVersion newConfig = new DcConfigVersion();
					newConfig.setAppId(appId);
					newConfig.setChangeType(ChangeType.ADD.getCode());
					newConfig.setConfigDesc(configVersion.getConfigDesc());
					newConfig.setConfigKey(configVersion.getConfigKey());
					newConfig.setConfigValue(configVersion.getConfigValue());
					newConfig.setCreateTime(new Date());
					newConfig.setCreateUser(user.getName());
					newConfig.setEnvId(envId);
					newConfig.setSensitive(configVersion.getSensitive());
					newConfig.setVersion(version.getId());
					newConfig.setParentId(configVersion.getAppId());
					configVersions.add(newConfig);
				}
			}
//			if (!CollectionUtils.isEmpty(del)) {
//				List<DcConfigVersion> versions = this.getDcConfigVersion(del, envId);
//				for (DcConfigVersion configVersion : versions) {
//					DcConfigVersion newConfig = new DcConfigVersion();
//					newConfig.setAppId(appId);
//					newConfig.setChangeType(ChangeType.DEL.getCode());
//					newConfig.setConfigDesc(configVersion.getConfigDesc());
//					newConfig.setConfigKey(configVersion.getConfigKey());
//					newConfig.setConfigValue(configVersion.getConfigValue());
//					newConfig.setCreateTime(new Date());
//					newConfig.setCreateUser(user.getName());
//					newConfig.setEnvId(envId);
//					newConfig.setSensitive(configVersion.getSensitive());
//					newConfig.setVersion(version.getId());
//					newConfig.setParentId(configVersion.getAppId());
//					configVersions.add(newConfig);
//				}
//			}
			List<DcConfigVersion> versions = this.getDcConfigVersion(Arrays.asList(appId), envId);
			if (!CollectionUtils.isEmpty(versions)) {
				versions.forEach(action->{
					if (del.contains(action.getParentId())){
						action.setChangeType(ChangeType.DEL.getCode());
					}else {
						action.setChangeType(ChangeType.OLD.getCode());
					}
					action.setVersion(version.getId());
					action.setCreateTime(new Date());
					action.setCreateUser(user.getName());
				});
				configVersions.addAll(versions);
			}
			if (!CollectionUtils.isEmpty(configVersions)) {
				dcConfigVersionService.insertBatch(duplicateRemoval(configVersions));
			}
			DcEnv env = dcEnvService.selectById(envId);
			DcApp app = dcAppService.selectById(appId);
			clearCache(app.getAppName(), env.getEnvName());
		}
	}

	// 去重 后面覆盖前面
	private List<DcConfigVersion> duplicateRemoval(List<DcConfigVersion> versions) {
		Map<String, DcConfigVersion> map = this.ListToMap(versions);
		return Lists.newArrayList(map.values());
	}

	// 获取项目最新配置
	private List<DcConfigVersion> getDcConfigVersion(List<Integer> ids, Integer envId) {
		List<DcConfigVersion> configVersions = new ArrayList<>();
		for (Integer id : ids) {
			Long maxVersion = dcConfigVersionService.maxVersion(id, envId);
			if (maxVersion != null) {
				DcConfigVersion entity = new DcConfigVersion();
				entity.setAppId(id);
				entity.setEnvId(envId);
				entity.setVersion(maxVersion);
				Wrapper<DcConfigVersion> wrapper = new EntityWrapper<DcConfigVersion>(entity);
				wrapper.ne("change_type", ChangeType.DEL.getCode());
				List<DcConfigVersion> list = dcConfigVersionService.selectList(wrapper);
				if (!CollectionUtils.isEmpty(list)) {
					configVersions.addAll(list);
				}
			}
		}
		return configVersions;
	}

	/**
	 * 获取父项目树
	 */
	@RequestMapping(value = "/parentTree")
	@ResponseBody
	public List<ZTreeNode> parentTree(Integer appId, Integer envId) {
		List<ZTreeNode> nodes = new ArrayList<>();
		DcApp entity = new DcApp();
		Wrapper<DcApp> wrapper = new EntityWrapper<DcApp>(entity);
		wrapper.ne("id", appId);
		List<DcApp> apps = dcAppService.selectList(wrapper);
		DcAppParent appParent = new DcAppParent();
		appParent.setEnvId(envId);
		appParent.setAppId(appId);
		Wrapper<DcAppParent> wrapper2 = new EntityWrapper<DcAppParent>(appParent);
		List<DcAppParent> appParents = dcAppParentService.selectList(wrapper2);
		List<Integer> ids = new ArrayList<>();
		if (!CollectionUtils.isEmpty(appParents)) {
			appParents.forEach(ac -> ids.add(ac.getParentAppId()));
		}
		if (!CollectionUtils.isEmpty(apps)) {
			for (DcApp app : apps) {
				ZTreeNode node = new ZTreeNode();
				node.setId(app.getId().longValue());
				node.setIsOpen(false);
				node.setName(app.getAppName());
				if (ids.contains(app.getId())) {
					node.setChecked(true);
				} else {
					node.setChecked(false);
				}
				nodes.add(node);
			}
		}
		return nodes;
	}

	private Map<String, DcConfigVersion> ListToMap(List<DcConfigVersion> list) {
		Map<String, DcConfigVersion> map = new HashMap<String, DcConfigVersion>();
		for (DcConfigVersion config : list) {
			if (map.containsKey(config.getConfigKey())) {// 如果前面的配置是父项目的配置后面项目也是父项目的配置不覆盖
				if (map.get(config.getConfigKey()).getParentId() != null && config.getParentId() != null) {
					break;
				}
				map.put(config.getConfigKey(), config);
			}else {
				map.put(config.getConfigKey(), config);
			}
			
		}
		return map;
	}

	/**
	 * 跳转到配置预页面
	 */
	@RequestMapping("/dcConfig_preview")
	public String dcConfigPreview(Integer appId, Integer envId, Model model) {
		DcConfig dcConfig = new DcConfig();
		dcConfig.setAppId(appId);
		dcConfig.setEnvId(envId);
		Wrapper<DcConfig> wrapper = new EntityWrapper<DcConfig>(dcConfig);
		wrapper.ne("status", ConfigStatus.DEL.getCode());
		List<DcConfig> configs = dcConfigService.selectList(wrapper);
		List<DcConfigVersion> dcConfigVersions = dcAppParentService.getAllParentConfig(appId, envId);
		Map<String, DcConfigVersion> map = this.ListToMap(dcConfigVersions);
		if (!CollectionUtils.isEmpty(configs)) {
			for (DcConfig config : configs) {
				DcConfigVersion configVersion = new DcConfigVersion();
				BeanUtils.copyProperties(config, configVersion);
				map.put(configVersion.getConfigKey(), configVersion);
			}
		}
		StringBuffer confStr = new StringBuffer();
		for (String key : map.keySet()) {
			DcConfigVersion node = map.get(key);
			if (node.getSensitive() == 1 && !ShiroKit.hasPermission(Const.SENSITIVE_URL)) {
				node.setConfigValue("******");
			}
			confStr.append("#");
			confStr.append(node.getConfigDesc());
			confStr.append("<br/>");
			confStr.append(node.getConfigKey());
			confStr.append("=");
			confStr.append(node.getConfigValue());
			confStr.append("<br/>");
		}
		model.addAttribute("confStr", confStr.toString());
		LogObjectHolder.me().set(dcConfig);
		return PREFIX + "dcConfig_preview.html";
	}

	/**
	 * 跳转到修改配置项
	 */
	@RequestMapping("/dcConfig_update/{dcConfigId}")
	public String dcConfigUpdate(@PathVariable Integer dcConfigId, Model model) {
		DcConfig dcConfig = dcConfigService.selectById(dcConfigId);
		if (dcConfig.getSensitive() == 1 && !ShiroKit.hasPermission(Const.SENSITIVE_URL)) {
			dcConfig.setConfigValue("******");
		}
		model.addAttribute("item", dcConfig);
		LogObjectHolder.me().set(dcConfig);
		return PREFIX + "dcConfig_edit.html";
	}

	/**
	 * 获取配置项列表
	 */
	@RequestMapping(value = "/list")
	@ResponseBody
	public Object list(PageBT pageBT, Integer appId, Integer envId, String key) {
		DcConfig entity = new DcConfig();
		entity.setAppId(appId);
		entity.setEnvId(envId);
		Wrapper<DcConfig> wrapper = new EntityWrapper<>(entity);
		if (!StringUtils.isEmpty(key)) {
			wrapper.like("config_key", key);
		}
		Page<DcConfig> page = dcConfigService.selectPage(new Page<>(pageBT.getPageNumber(), pageBT.getPageSize()),
				wrapper);
		Page<ConfigDto> page2 = new Page<>();
		BeanUtils.copyProperties(page, page2);
		page2.setRecords(null);
		List<ConfigDto> dtos = new ArrayList<>();
		page2.setRecords(dtos);
		List<DcConfig> prizes = page.getRecords();
		if (!CollectionKit.isEmpty(prizes)) {
			prizes.forEach(pz -> {
				ConfigDto dto = new ConfigDto();
				BeanUtils.copyProperties(pz, dto);
				if (dto.getSensitive() == 1 && !ShiroKit.hasPermission(Const.SENSITIVE_URL)) {
					dto.setConfigValue("******");
				}
				dto.setStatusDesc(ConfigStatus.valueOf(dto.getStatus()));
				dtos.add(dto);
			});
		}
		return new PageInfoBT<>(page2);
	}

	/**
	 * 恢复配置
	 */
	@Permission
	@RequestMapping(value = "/recovery")
	@ResponseBody
	@Transactional
	public Object recovery(Integer appId, Integer envId) {
		DcEnv env = dcEnvService.selectById(envId);
		if (env == null) {
			return new ErrorTip(500, "环境不存在");
		}
		DcApp app = dcAppService.selectById(appId);
		if (app == null) {
			return new ErrorTip(500, "项目不存在");
		}
		DcConfig entity = new DcConfig();
		entity.setAppId(appId);
		entity.setEnvId(envId);
		Wrapper<DcConfig> wrapper = new EntityWrapper<DcConfig>(entity);
		dcConfigService.delete(wrapper);
		DcConfigVersion configVersion = new DcConfigVersion();
		configVersion.setAppId(appId);
		configVersion.setEnvId(envId);
		ShiroUser user = ShiroKit.getUser();
		configVersion.setVersion(dcConfigVersionService.maxVersion(entity.getAppId(), entity.getEnvId()));
		Wrapper<DcConfigVersion> wrapper2 = new EntityWrapper<DcConfigVersion>(configVersion);
		wrapper2.ne("change_type", ChangeType.DEL.getCode());
		wrapper2.isNull("parent_id");
		List<DcConfigVersion> list = dcConfigVersionService.selectList(wrapper2);
		if (!CollectionUtils.isEmpty(list)) {
			List<DcConfig> entityList = new ArrayList<>();
			list.forEach(action -> {
				DcConfig config = new DcConfig();
				config.setAppId(appId);
				config.setEnvId(envId);
				config.setConfigDesc(action.getConfigDesc());
				config.setConfigKey(action.getConfigKey());
				config.setConfigValue(action.getConfigValue());
				config.setCreateTime(new Date());
				config.setCreateUser(user.getName());
				config.setSensitive(action.getSensitive());
				config.setStatus(ConfigStatus.PUB.getCode());
				entityList.add(config);
			});
			dcConfigService.insertBatch(entityList);
		}
		return SUCCESS_TIP;
	}

	/**
	 * 上传配置
	 */
	@Permission
	@RequestMapping(value = "/upload")
	@ResponseBody
	@Transactional
	public Object upload(Integer appId, Integer envId, @RequestPart("file") MultipartFile file) {
		DcEnv env = dcEnvService.selectById(envId);
		if (env == null) {
			return new ErrorTip(500, "环境不存在");
		}
		DcApp app = dcAppService.selectById(appId);
		if (app == null) {
			return new ErrorTip(500, "项目不存在");
		}
		SafeProperties properties = new SafeProperties();
		try {
			properties.load(new ByteArrayInputStream(file.getBytes()), "UTF-8");
			dcConfigService.upload(appId, envId, properties);
		} catch (IOException e) {
			return new ErrorTip(500, e.getMessage());
		}
		return SUCCESS_TIP;
	}

	/**
	 * 下载配置
	 */
	@Permission
	@RequestMapping(value = "/download")
	@ResponseBody
	public void download(Integer appId, Integer envId, HttpServletResponse response) {
		DcConfig entity = new DcConfig();
		entity.setAppId(appId);
		entity.setEnvId(envId);
		Wrapper<DcConfig> wrapper = new EntityWrapper<DcConfig>(entity);
		List<DcConfig> configs = dcConfigService.selectList(wrapper);
		SafeProperties properties = new SafeProperties();
		for (DcConfig node : configs) {
			if (node.getSensitive() == 1 && !ShiroKit.hasPermission(Const.SENSITIVE_URL)) {
				node.setConfigValue("******");
			}
			properties.setProperty(node.getConfigKey(), node.getConfigValue(), node.getConfigDesc());
		}
		DcApp app = dcAppService.selectById(appId);
		response.setContentType("application/force-download");
		response.addHeader("Content-Disposition", "attachment;fileName=" + app.getAppName() + ".properties");
		try {
			properties.store(response.getOutputStream());
		} catch (IOException e) {
		}
	}

	/**
	 * 新增配置项
	 */
	@Permission
	@RequestMapping(value = "/add")
	@ResponseBody
	@Transactional
	public Object add(AddConfigReq dcConfig) {
		if (dcConfig.getConfigKey() == null) {
			return new ErrorTip(500, "配置key不能为空");
		}
		DcEnv env = dcEnvService.selectById(dcConfig.getEnvId());
		if (env == null) {
			return new ErrorTip(500, "环境不存在");
		}
		DcApp app = dcAppService.selectById(dcConfig.getAppId());
		if (app == null) {
			return new ErrorTip(500, "项目不存在");
		}
		dcConfig.setConfigKey(dcConfig.getConfigKey().trim());
		DcConfig entity = new DcConfig();
		entity.setAppId(dcConfig.getAppId());
		entity.setEnvId(dcConfig.getEnvId());
		entity.setConfigKey(dcConfig.getConfigKey());
		Wrapper<DcConfig> wrapper = new EntityWrapper<DcConfig>(entity);
		int count = dcConfigService.selectCount(wrapper);
		if (count > 0) {
			return new ErrorTip(500, "配置已存在");
		}
		dcConfig.setCreateTime(new Date());
		ShiroUser user = ShiroKit.getUser();
		dcConfig.setCreateUser(user.getName());
		dcConfig.setStatus(ConfigStatus.NEW.getCode());
		if (dcConfig.getTrim() != null && dcConfig.getTrim() == 1 && dcConfig.getConfigValue() != null) {
			dcConfig.setConfigValue(dcConfig.getConfigValue().trim());
		}
		dcConfigService.insert(dcConfig);
		return SUCCESS_TIP;
	}

	/**
	 * 删除配置项
	 */
	@Permission
	@RequestMapping(value = "/delete")
	@ResponseBody
	@Transactional
	public Object delete(@RequestParam Integer dcConfigId) {
		DcConfig config = dcConfigService.selectById(dcConfigId);
		if (ConfigStatus.NEW.getCode().equals(config.getStatus())) {
			dcConfigService.deleteById(config.getId());
		} else {
			config.setStatus(ConfigStatus.DEL.getCode());
			config.setUpdateTime(new Date());
			ShiroUser user = ShiroKit.getUser();
			config.setUpdateUser(user.getName());
			dcConfigService.updateById(config);
		}
		return SUCCESS_TIP;
	}

	/**
	 * 修改配置项
	 */
	@Permission
	@RequestMapping(value = "/update")
	@ResponseBody
	@Transactional
	public Object update(DcConfig dcConfig) {
		DcConfig old = dcConfigService.selectById(dcConfig.getId());
		if (old == null) {
			return new ErrorTip(500, "配置项不存在");
		}
		if (old.getSensitive() == 1 && !ShiroKit.hasPermission(Const.SENSITIVE_URL)) {
			return new ErrorTip(500, "无权修改敏感配置");
		}
//		if (!old.getConfigKey().equals(dcConfig.getConfigKey())) {
//			return new ErrorTip(500, "无法修改配置key");
//		}
		dcConfig.setConfigKey(old.getConfigKey());
		dcConfig.setUpdateTime(new Date());
		ShiroUser user = ShiroKit.getUser();
		dcConfig.setUpdateUser(user.getName());
		if (ConfigStatus.UPD.getCode().equals(old.getStatus()) || ConfigStatus.PUB.getCode().equals(old.getStatus())) {
			dcConfig.setStatus(ConfigStatus.UPD.getCode());
		} else if (ConfigStatus.DEL.getCode().equals(old.getStatus())) {
			dcConfig.setStatus(ConfigStatus.UPD.getCode());
		} else if (ConfigStatus.NEW.getCode().equals(old.getStatus())) {
			dcConfig.setStatus(ConfigStatus.NEW.getCode());
		}
		dcConfigService.updateById(dcConfig);
		return SUCCESS_TIP;
	}

	/**
	 * 配置项详情
	 */
	@RequestMapping(value = "/detail/{dcConfigId}")
	@ResponseBody
	public Object detail(@PathVariable("dcConfigId") Integer dcConfigId) {
		DcConfig dto = dcConfigService.selectById(dcConfigId);
		if (dto.getSensitive() == 1 && !ShiroKit.hasPermission(Const.SENSITIVE_URL)) {
			dto.setConfigValue("******");
		}
		return dto;
	}

	/**
	 * 应用列表
	 */
	@RequestMapping(value = "/appList")
	@ResponseBody
	public Object applist() {
		ShiroUser user = ShiroKit.getUser();
		List<DcApp> apps = dcAppService.getUserApp(user.getId());
		List<SelectNode> selectNodes = new ArrayList<>();
		if (!CollectionUtils.isEmpty(apps)) {
			apps.forEach(app -> {
				SelectNode node = new SelectNode();
				node.setId(app.getId().toString());
				node.setName(app.getAppName());
				selectNodes.add(node);
			});
		}
		return selectNodes;
	}

	/**
	 * 环境列表
	 */
	@RequestMapping(value = "/envList")
	@ResponseBody
	public Object envlist() {
	    ShiroUser user = ShiroKit.getUser();
	    List<Integer> roleids = user.getRoleList();
	    Wrapper<DcEnvRole> envwrapper = new EntityWrapper<>();
	    envwrapper.in("role_id", roleids);
	    List<DcEnvRole> dcEnvRoles = envRoleService.selectList(envwrapper);
	    List<Integer> envIds = dcEnvRoles.stream().map(DcEnvRole::getEnvId).collect(Collectors.toList());
		Wrapper<DcEnv> wrapper = new EntityWrapper<>();
		List<DcEnv> apps = dcEnvService.selectList(wrapper);
		List<SelectNode> selectNodes = new ArrayList<>();
		if (!CollectionUtils.isEmpty(apps)) {
			apps.forEach(env -> {
			    if (envIds.contains(env.getId())) {
			        SelectNode node = new SelectNode();
	                node.setId(env.getId().toString());
	                node.setName(env.getEnvName());
	                selectNodes.add(node);
			    }
			});
		}
		return selectNodes;
	}

	/**
	 * 发布
	 */
	@Permission
	@RequestMapping(value = "/pub")
	@ResponseBody
	@Transactional
	public Object pub(Integer appId, Integer envId) {
		DcConfig entity = new DcConfig();
		entity.setAppId(appId);
		entity.setEnvId(envId);
		Wrapper<DcConfig> wrapper = new EntityWrapper<DcConfig>(entity);
		ShiroUser user = ShiroKit.getUser();
		List<DcConfig> configs = dcConfigService.selectList(wrapper);
		if (!CollectionUtils.isEmpty(configs)) {
			DcVersion version = new DcVersion();
			version.setCreateTime(new Date());
			dcVersionService.insert(version);
			List<DcConfigVersion> configVersions = new ArrayList<>();
			configs.forEach(config -> {
				DcConfigVersion configVersion = new DcConfigVersion();
				BeanUtils.copyProperties(config, configVersion);
				configVersion.setId(null);
				configVersion.setVersion(version.getId());
				if (ConfigStatus.NEW.getCode().equals(config.getStatus())) {
					configVersion.setChangeType(ChangeType.ADD.getCode());
				} else if (ConfigStatus.UPD.getCode().equals(config.getStatus())) {
					configVersion.setChangeType(ChangeType.UPDATE.getCode());
				} else if (ConfigStatus.DEL.getCode().equals(config.getStatus())) {
					configVersion.setChangeType(ChangeType.DEL.getCode());
				} else {
					configVersion.setChangeType(ChangeType.OLD.getCode());
				}
				configVersion.setCreateTime(new Date());
				configVersion.setCreateUser(user.getName());
				configVersions.add(configVersion);
				if (ConfigStatus.DEL.getCode().equals(config.getStatus())) {
					dcConfigService.deleteById(config.getId());
				} else {
					config.setStatus(ConfigStatus.PUB.getCode());
					dcConfigService.updateById(config);
				}
			});
			// 父项目配置获取
			List<DcConfigVersion> dcConfigVersions = dcAppParentService.getAllParentConfig(appId, envId);
			if (!CollectionUtils.isEmpty(dcConfigVersions)) {
			    for (DcConfigVersion configVersion : dcConfigVersions) {
			        configVersion.setChangeType(ChangeType.OLD.getCode());
			        configVersion.setParentId(configVersion.getAppId());
			        configVersion.setAppId(appId);
			        configVersion.setCreateTime(new Date());
			        configVersion.setCreateUser(user.getName());
			        configVersion.setVersion(version.getId());
			    }
			    configVersions.addAll(dcConfigVersions);
			    List<DcConfigVersion> configVersions2 = this.duplicateRemoval2(configVersions);
			    dcConfigVersionService.insertBatch(configVersions2);
			    // 如果次项目存在子项目 需要发布子项目
	            pubSubApp(appId, envId, configVersions2,user);
			}else {
			    dcConfigVersionService.insertBatch(configVersions);
			    // 如果次项目存在子项目 需要发布子项目
	            pubSubApp(appId, envId, configVersions,user);
			}
			
		}
		DcEnv env = dcEnvService.selectById(envId);
		DcApp app = dcAppService.selectById(appId);
		clearCache(app.getAppName(), env.getEnvName());
		return SUCCESS_TIP;
	}
	
	private List<DcConfigVersion> duplicateRemoval2(List<DcConfigVersion> dcConfigVersions){
	    List<DcConfigVersion> configVersions = new ArrayList<>();
	    if (!CollectionUtils.isEmpty(dcConfigVersions)) {
	        Map<String, DcConfigVersion> map = new HashMap<>();
	        for (DcConfigVersion configVersion : dcConfigVersions) {
	            if (!map.containsKey(configVersion.getConfigKey())) {
	                map.put(configVersion.getConfigKey(), configVersion);
	            }
	        }
	        return Lists.newArrayList(map.values());
	    }
	    return configVersions;
	}
	
	// 发布子项目
	public void pubSubApp(Integer appId, Integer envId, List<DcConfigVersion> configVersions,ShiroUser user) {
		if (CollectionUtils.isEmpty(configVersions)) {
			return;
		}
		DcAppParent entity = new DcAppParent();
		entity.setParentAppId(appId);
		entity.setEnvId(envId);
		Wrapper<DcAppParent> wrapper = new EntityWrapper<DcAppParent>(entity);
		List<DcAppParent> appParents = dcAppParentService.selectList(wrapper);
		if (CollectionUtils.isEmpty(appParents)) {
			return;
		}
		for (DcAppParent appParent : appParents) {
			List<DcConfigVersion> newConfigVersion = new ArrayList<>();
			DcVersion version = new DcVersion();
			version.setCreateTime(new Date());
			dcVersionService.insert(version);
			for (DcConfigVersion configVersion : configVersions) {// 父项目配置
				DcConfigVersion dcConfigVersion = new DcConfigVersion();
				dcConfigVersion.setAppId(appParent.getAppId());
				dcConfigVersion.setChangeType(configVersion.getChangeType());
				dcConfigVersion.setConfigDesc(configVersion.getConfigDesc());
				dcConfigVersion.setConfigKey(configVersion.getConfigKey());
				dcConfigVersion.setConfigValue(configVersion.getConfigValue());
				dcConfigVersion.setCreateTime(new Date());
				dcConfigVersion.setCreateUser(user.getName());
				dcConfigVersion.setEnvId(envId);
				dcConfigVersion.setParentId(appId);
				dcConfigVersion.setSensitive(configVersion.getSensitive());
				dcConfigVersion.setVersion(version.getId());
				newConfigVersion.add(dcConfigVersion);
			}
			List<DcConfigVersion> list = this.getDcConfigVersion(Arrays.asList(appParent.getAppId()), envId);// 子项目配置
			if(!CollectionUtils.isEmpty(list)) {
				for (DcConfigVersion configVersion : list) {
					if (!appId.equals(configVersion.getParentId())) {
						DcConfigVersion dcConfigVersion = new DcConfigVersion();
						dcConfigVersion.setAppId(configVersion.getAppId());
						dcConfigVersion.setParentId(configVersion.getParentId());
						dcConfigVersion.setChangeType(ChangeType.OLD.getCode());
						dcConfigVersion.setConfigDesc(configVersion.getConfigDesc());
						dcConfigVersion.setConfigKey(configVersion.getConfigKey());
						dcConfigVersion.setConfigValue(configVersion.getConfigValue());
						dcConfigVersion.setCreateTime(new Date());
						dcConfigVersion.setCreateUser(user.getName());
						dcConfigVersion.setEnvId(envId);
						dcConfigVersion.setSensitive(configVersion.getSensitive());
						dcConfigVersion.setVersion(version.getId());
						newConfigVersion.add(dcConfigVersion);
					}
				}
			}
			if (!CollectionUtils.isEmpty(newConfigVersion)) {
				this.dcConfigVersionService.insertBatch(this.duplicateRemoval(newConfigVersion));
				DcEnv env = dcEnvService.selectById(envId);
				DcApp app = dcAppService.selectById(appParent.getAppId());
				clearCache(app.getAppName(), env.getEnvName());
			}
		}
		
	}

	public void clearCache(String appName, String env) {
		String pattern = String.format("%s_%s_*", appName, env);
		Set<String> keys = redisTemplate.keys(pattern);
		redisTemplate.delete(keys);
	}
}
